#include <sum_csr.h>
#include <sum_eclic.h>
#include <sum_gpio.h>
#include <sum_rcu.h>
#include <sum_usart.h>
#include <sum_wfi.h>
#include <sys_mem.h>
#include <util_fifo.h>
#include <util_trans.h>

#define APB2_FREQ_DEFAULT 8000000
#define BUF_SIZE_2_POWER 8

// RCU中将GPIOA和USART0上电
static void _enable_gpioa_usart0(void) {
	rcu_apb2_s apb2 = {
		.apb2_0_7.GPIOA = 1,
		.apb2_8_15.USART0 = 1,
	};
	rcu_apb2_en_di(apb2);
}

// 配置A9为AF输出，A10为浮空输入。
static void _setup_gpafio(void) {
	gpio_ctl_8_15_s gpioa_ctl1 = {
		// A9的配置：低速输出、AF、推挽
		.pin9_ctl = GPIO_OUT_AF_PP_2MHZ,

		// A10的配置：输入、浮空
		.pin10_ctl = GPIO_IN_FLOAT,
	};
	gpio_setup_pin_8_15(GPIOA_Q, gpioa_ctl1);
}

// USART0打开可发送中断，关闭未读中断。
static void _enable_ri(void) {
	usart_ctl0_expl_s ctl0 = {
		.usart_en = 1,
		.trans_en = 1,
		.recv_en = 1,
		.unread_overrun_inter_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// USART0打开可发送中断和未读中断
static void _enable_rti(void) {
	usart_ctl0_expl_s ctl0 = {
		.usart_en = 1,
		.trans_en = 1,
		.recv_en = 1,
		.trans_avl_inter_en = 1,
		.unread_overrun_inter_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// 串口输入输出缓冲区
static struct {
	fifo8_v fifo8;
	u8_s buffer_a[1 << BUF_SIZE_2_POWER];
} g_fifo8_in, g_fifo8_out;

static void _init_fifo() {
	fifo8_init(&(g_fifo8_in.fifo8), BUF_SIZE_2_POWER);
	fifo8_init(&(g_fifo8_out.fifo8), BUF_SIZE_2_POWER);
}

// 串口中断
static void _usart0_irq(void) {
	fifo8_v* out_fifo_p = &(g_fifo8_out.fifo8);
	fifo8_v* in_fifo_p = &(g_fifo8_in.fifo8);
	while (1) {
		usart_stat_expl_s stat = usart_get_stat(USART0_Q);
		// 优先解决未读
		if (stat.has_unread) {
			u32_s byte = usart_rn_byte(USART0_Q);
			fifo8_in_byte(in_fifo_p, byte);
			continue;
		}
		// 确定无未读数据后进入数据发送分支。
		// 若无数据需要发送，关闭可发送中断后返回。
		else if (!fifo8_has_data(out_fifo_p)) {
			_enable_ri();
			return;
		}
		// 至此，确定无未读数据，且有数据需要发送。检查是否可发送数据。
		// 若可发送，再次（从是否有未读数据）开始检查并进行相应处理。
		else if (stat.trans_avl) {
			u32_s byte = fifo8_out_byte(out_fifo_p);
			usart_wn_byte(USART0_Q, byte);
			continue;
		}
		// 至此，确定无未读数据，有数据需要发送，但当前不可发送。应直接返回。
		// （理论上应该不可能进入此处）
		else {
			return;
		}
	}
}

// 串口配置
static void _setup_usart(void) {
	_enable_gpioa_usart0();
	_setup_gpafio();
	usart_set_baud_rate(USART0_Q, 115200, APB2_FREQ_DEFAULT);
	_enable_ri();
}

// 中断配置
static void _setup_interrupt(void) {
	// 中断入口地址设为自带的中断入口
	csr_set_default_exti_entry();
	// 中断向量表
	static const __attribute__((aligned(512))) eclic_irqvec_t ivt = {
		.irq_entry_fa[IRQNO_USART0] = _usart0_irq,
	};
	eclic_set_ivt_base(&ivt);
	// 设置中断level和priority，其中priority域占据全部bit，无level。
	eclic_set_level_priority_bit_amount(NLBITS_LEVEL_0_PRIORITY_4);
	eclic_clicint_expl_s clicint = {
		.inter_en.value = 1,
		.attr.vector_mode = 0,
		.level_priority = eclic_set_level_priority(
			NLBITS_LEVEL_0_PRIORITY_4, 0, 0),
	};
	eclic_setup_inter_expl(IRQNO_USART0, clicint);
	// 打开全局中断
	csr_enable_global_interrupt();
}

// 对字节进行处理
static u32_s _deal_ch(u32_s ch) {
	if (ch >= 'a' && ch <= 'z') {
		return ch - 'a' + 'A';
	} else if (ch >= 'A' && ch <= 'Z') {
		return ch - 'A' + 'a';
	} else {
		return ch;
	}
}

__attribute__((noreturn, section(".MAIN"))) void user_main(void) {
	mem_scatter_load();

	// 初始化fifo缓冲区
	_init_fifo();
	// 串口配置
	_setup_usart();
	// 异常入口地址直接设为0（理论上该例程中不可能发生异常）。
	csr_enable_eclic_set_entry(0);
	// 中断配置
	_setup_interrupt();

	fifo8_v* out_fifo_p = &(g_fifo8_out.fifo8);
	fifo8_v* in_fifo_p = &(g_fifo8_in.fifo8);

	while (1) {
		wfi();

		// 若收到了串口字节，进行处理。
		while (fifo8_has_data(in_fifo_p)) {
			u32_s in_ch = fifo8_out_byte(in_fifo_p);
			u32_s out_ch = _deal_ch(in_ch);
			// 将要输出的字符放进缓冲区
			fifo8_in_byte(out_fifo_p, out_ch);
			// 开启可发送中断
			_enable_rti();
		}
	}
}
